package icasue.stronger.config;

import icasue.base.register.ICasuePluginsRegister;
import icasue.stronger.register.StrongerProxyBuffer;
import icasue.stronger.register.StrongerProxyClassPathBeanDefinitionScannerRegister;
import icasue.stronger.wareable.logicstronger.StrongerAdvice;
import icasue.stronger.wareable.logicstronger.logicsupport.LoggerStrongerLogic;
import icasue.stronger.wareable.nameconvert.BeanNameTransFor;
import icasue.stronger.wareable.nameconvert.DefaultBeanNameTransFor;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.util.StringUtils;

import javax.validation.constraints.NotNull;
import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.List;

/**
 * @Author: Qiao Hang
 * @CreateDate: 2021/12/1 上午10:02
 * @UpdateDate:
 * @Description:
 */
public class PluginStrongerAdviceBeanRegisterGroup {

    public static class RegisterStrongerAdvice extends ICasuePluginsRegister<EnvironmentStrongerScanConfig>{

        @Override
        public String environmentPropertiesPrefix() {
            return "proxy.stronger";
        }

        @Override
        public Class<EnvironmentStrongerScanConfig> environmentPropertiesType() {
            return EnvironmentStrongerScanConfig.class;
        }

        @Override
        protected Integer order() {
            return Integer.MAX_VALUE;
        }

        @Override
        protected @NotNull Boolean checkRegister() {
            return configProperties.enable;
        }

        @Override
        protected void previousRegister() {
            StrongerProxyBuffer.beanFactory = super.beanFactory;
        }

        @Override
        public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
            //read scan infos from environment.
            if(configProperties != null){
                for (EnvironmentStrongerScanConfig.EnvironmentStrongerGroup configGroup : configProperties.getGroups()) {
                    this.readConfigInvokeScanner(
                            registry,
                            configGroup.getStrongerAdvice(),
                            configGroup.getStrongerAdviceRef(),
                            configGroup.getBeanNameStoreTransForLogic(),
                            configGroup.getBasePackages(),
                            configGroup.getMarkedAnnotation(),
                            configGroup.getExcludeRegex()
                    );
                }
            }
        }


        /**
         * init scan,from applicationConfig, or environment config.
         * @param registry
         * @param strongerAdvice
         * @param strongerAdviceRef
         * @param beanNameStoreTransForLogic
         * @param packages
         * @param markedAnnotation
         * @param excludeRegex
         */
        private void readConfigInvokeScanner(BeanDefinitionRegistry registry,
                                             Class<? extends StrongerAdvice> strongerAdvice,
                                             String strongerAdviceRef,
                                             Class<? extends BeanNameTransFor> beanNameStoreTransForLogic,
                                             List<String> packages,
                                             Class<? extends Annotation> markedAnnotation,
                                             List<String> excludeRegex) {

            //create ClassPathBeanDefinitionScanner,used for generic RowBeanDefinition.
            StrongerProxyClassPathBeanDefinitionScannerRegister scannerRegister =
                    new StrongerProxyClassPathBeanDefinitionScannerRegister(registry);

            //Method invoke stronger reference.
            if(!StrongerAdvice.class.equals(strongerAdvice)){
                try {
                    scannerRegister.setStrongerAdvice(strongerAdvice);
                }catch (Exception e){
                    // -----
                }
            }
            if(StringUtils.hasText(strongerAdviceRef)){
                scannerRegister.setStrongerAdviceRef(strongerAdviceRef);
            }

            //Set BeanNameTransForLogic class ,used on exist duplicate BeanDefinitions.
            if(!DefaultBeanNameTransFor.class.equals(beanNameStoreTransForLogic)){
                try {
                    BeanNameTransFor beanNameStoreTransForBean = BeanUtils.instantiateClass(beanNameStoreTransForLogic,BeanNameTransFor.class);
                    scannerRegister.setBeanNameTransFor(beanNameStoreTransForBean);
                }catch (Exception e){
                    // -----
                }
            }

            //construct packages which need to scan.
            List<String> basePackages = new ArrayList<>();
            for(String basePackage : packages){
                if(StringUtils.hasText(basePackage)){
                    basePackages.add(basePackage);
                }
            }

            //get marked annotation.
            if(!Annotation.class.equals(markedAnnotation)){
                scannerRegister.setMarkedAnnotation(markedAnnotation);
            }

            //get markedExcludeClass,these classes will not be proxy.
            scannerRegister.setMarkerExclude(excludeRegex);

            //register scanner's filters.
            scannerRegister.registerFilter();
            //do scan.
            scannerRegister.doScan(StringUtils.toStringArray(basePackages));
        }

    }
}
